package com.ticket.system.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import com.google.common.collect.Lists;
import com.ticket.common.constant.CacheConstants;
import com.ticket.common.constant.PerformConstants;
import com.ticket.common.core.domain.model.LoginUser;
import com.ticket.common.core.redis.RedisCache;
import com.ticket.common.exception.ServiceException;
import com.ticket.common.exception.base.BaseException;
import com.ticket.common.utils.Const;
import com.ticket.common.utils.DateUtils;
import com.ticket.common.utils.SecurityUtils;
import com.ticket.common.utils.StringUtils;
import com.ticket.system.domain.*;
import com.ticket.system.domain.vo.OrderVo;
import com.ticket.system.domain.vo.SessionTicketVO;
import com.ticket.system.domain.vo.SessionVo;
import com.ticket.system.mapper.*;
import com.ticket.system.service.*;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 场次Service业务层处理
 * 
 * @author ruoyi
 * @date 2023-09-26
 */
@Service
@AllArgsConstructor
public class YanchuSessionServiceImpl implements IYanchuSessionService 
{
    private static final Logger logger = LoggerFactory.getLogger(YanchuSessionServiceImpl.class);
    @Autowired
    private YanchuSessionMapper yanchuSessionMapper;

    @Autowired
    private IYanchuSeatService yanchuSeatService;

    @Autowired
    private YanchuHallMapper yanchuHallMapper;
    @Autowired
    private YanchuTicketPriceMapper yanchuTicketPriceMapper;
    @Autowired
    private TYanchuReservedTicketMapper yanchuReservedTicketMapper;
    @Autowired
    private YanchuSeatMapper yanchuSeatMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IYanchuRefundOrderService iYanchuRefundOrderService;
    @Autowired
    private IYanchuRefundBackendOrderService iYanchuRefundBackendOrderService;
    @Autowired
    private YanchuPerformMapper yanchuPerformMapper;

    private WxMaService wxMaService;
    @Autowired
    private YanchuOrderMapper yanchuOrderMapper;
    @Value("${wx.miniapp.templateIdOrder}")
    private String templateId;
    @Value("${wx.miniapp.miniprogramState}")
    private String miniprogramState;
    /**
     * 查询场次
     * 
     * @param id 场次主键
     * @return 场次
     */
    @Override
    public YanchuSession selectYanchuSessionById(Long id)
    {
        YanchuSession session = yanchuSessionMapper.selectYanchuSessionById(id);
        if (null != session && null != session.getHallId()){
            YanchuHall yanchuHall = yanchuHallMapper.selectYanchuHallById(session.getHallId());
            if (null != yanchuHall){
                session.setHallName(yanchuHall.getHallName());
            }
        }
        if (null != session && null != session.getPerformId()){
            YanchuPerform yanchuPerform = yanchuPerformMapper.selectYanchuPerformById(session.getPerformId());
            if (null != yanchuPerform){
                session.setPerformName(yanchuPerform.getPerformName());
            }
        }
        return session;
    }

    /**
     * 查询场次列表
     * 
     * @param yanchuSession 场次
     * @return 场次
     */
    @Override
    public List<YanchuSession> selectYanchuSessionList(YanchuSession yanchuSession)
    {
        return yanchuSessionMapper.selectYanchuSessionList(yanchuSession);
    }

    @Override
    public List<SessionVo> selectSessionVoList(Long performId){
        return yanchuSessionMapper.selectSessionVoList(performId);
    }

    /**
     * 新增场次
     * 
     * @param yanchuSession 场次
     * @return 结果
     */
    @Override
    public int insertYanchuSession(YanchuSession yanchuSession)
    {
        Date startDate = DateUtils.parseDate(yanchuSession.getStartDate());
        Date endDate = DateUtils.parseDate(yanchuSession.getEndDate());
        //校验名称是否在当前演出下重复
        if (chackSessionName(null,yanchuSession.getPerformId(),yanchuSession.getSessionName())){
            throw new BaseException("场次名称已存在");
        }
        //校验剧场下时间是否重复
        /*if (chackSessionTime(null,null,yanchuSession.getHallId(),startDate,endDate)){
            throw new BaseException("在该剧场下演出场次时间存在重复");
        }*/

        LoginUser user = SecurityUtils.getLoginUser();
        yanchuSession.setStatus(0);
        yanchuSession.setPlayTime(startDate);
        yanchuSession.setEndTime(endDate);
        yanchuSession.setSessionDate(DateUtils.parseDate(DateUtils.dateTime(startDate)));
        yanchuSession.setCreateTime(DateUtils.getNowDate());
        yanchuSession.setOperaId(user.getUser().getOperaId());
        yanchuSession.setCreateBy(user.getUserId()+"");
        return yanchuSessionMapper.insertYanchuSession(yanchuSession);
    }

    /**
     * 校验剧场下时间是否重复
     *
     * @param performId
     * @param hallId
     * @param playTime
     * @param endTime
     * @return
     */
    private Boolean chackSessionTime(Long id,Long performId, Long hallId, Date playTime, Date endTime) {
        YanchuSession session = new YanchuSession();
        session.setPerformId(performId);
        session.setHallId(hallId);
        List<YanchuSession> sessions = yanchuSessionMapper.selectSessionList(session);
        if (CollectionUtils.isNotEmpty(sessions)){
            if (null != id){
                sessions.removeIf(s -> s.getId().equals(id));
            }
            for (YanchuSession sion : sessions) {
                if (playTime.compareTo(sion.getEndTime()) > 0 || endTime.compareTo(sion.getPlayTime()) < 0){
                    continue;
                }else {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 校验场次名称是否重复
     *
     * @param id
     * @param performId
     * @param sessionName
     * @return
     */
    private Boolean chackSessionName(Long id, Long performId, String sessionName) {
        List<YanchuSession> sessions = yanchuSessionMapper.selectSessionByPerFormId(performId);
        if (CollectionUtils.isNotEmpty(sessions)){
            for (YanchuSession sion : sessions) {
                if (null == id){
                    //新增校验
                    if (sessionName.equals(sion.getSessionName())){
                        return true;
                    }
                }else {
                    //编辑校验
                    if (sessionName.equals(sion.getSessionName())){
                        if (!id.equals(sion.getId())){
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * 修改场次
     * 
     * @param yanchuSession 场次
     * @return 结果
     */
    @Override
    public int updateYanchuSession(YanchuSession yanchuSession)
    {
        //校验名称是否在当前演出下重复
        if (StringUtils.isNotEmpty(yanchuSession.getSessionName())) {
            if (chackSessionName(yanchuSession.getId(), yanchuSession.getPerformId(), yanchuSession.getSessionName())) {
                throw new BaseException("场次名称已存在");
            }
        }
        if (StringUtils.isNotEmpty(yanchuSession.getStartDate()) && StringUtils.isNotEmpty(yanchuSession.getEndDate())) {
            YanchuSession byId = yanchuSessionMapper.selectYanchuSessionById(yanchuSession.getId());
//            if (Const.ZERO.equals(byId.getStatus())) {
                Date stratDate = DateUtils.parseDate(yanchuSession.getStartDate());
                Date endDate = DateUtils.parseDate(yanchuSession.getEndDate());
                if (stratDate.compareTo(byId.getPlayTime()) != 0
                        || endDate.compareTo(byId.getEndTime()) != 0) {
                    yanchuSession.setPlayTime(stratDate);
                    yanchuSession.setEndTime(endDate);
                    /*if (chackSessionTime(yanchuSession.getId(), null, yanchuSession.getHallId(), stratDate, endDate)) {
                        throw new BaseException("在该剧场下演出时间存在重复");
                    }*/
                    yanchuSession.setSessionDate(DateUtils.parseDate(DateUtils.dateTime(stratDate)));
                }
//            }
        }
        if (StringUtils.isNotEmpty(yanchuSession.getStartTicTime()) && StringUtils.isNotEmpty(yanchuSession.getEndTicTime())){
            Date stratDate = DateUtils.parseDate(yanchuSession.getStartTicTime());
            Date endDate = DateUtils.parseDate(yanchuSession.getEndTicTime());
            yanchuSession.setTicketStart(stratDate);
            yanchuSession.setTicketEnd(endDate);
        }
        yanchuSession.setUpdateTime(DateUtils.getNowDate());
        return yanchuSessionMapper.updateYanchuSession(yanchuSession);
    }
    /**
     * 上架场次
     *
     * @param sessionId 场次
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int up(Long sessionId){
        YanchuSession yanchuSession = yanchuSessionMapper.selectYanchuSessionById(sessionId);
        if(null == yanchuSession || yanchuSession.getStatus().equals(PerformConstants.SESSION_UP)){
            throw new ServiceException("发布失败！");
        }
        Integer count = yanchuSessionMapper.updateStatus(sessionId,PerformConstants.SESSION_UP,null,null);
        if(count <= 0){
            return count;
        }
        //停售重新发布
        if(yanchuSession.getStatus() == PerformConstants.SESSION_DOWN){
            int resCount = yanchuSeatService.reservedYanchuSeat(yanchuSession);
            logger.info("resCount:{}",resCount);
        }else{
            //上架初始化座位
            int seatCount = yanchuSeatService.initYanchuSeat(yanchuSession);
            logger.info("seatCount:{}",seatCount);
        }

//        if(count <= 0){
//            throw new ServiceException("发布座位信息失败！");
//        }
        return count;
    }

    /**
     * 批量删除场次
     * 
     * @param ids 需要删除的场次主键
     * @return 结果
     */
    @Override
    public int deleteYanchuSessionByIds(Long[] ids)
    {
        return yanchuSessionMapper.deleteYanchuSessionByIds(ids);
    }

    /**
     * 删除场次信息
     * 
     * @param id 场次主键
     * @return 结果
     */
    @Override
    public int deleteYanchuSessionById(Long id)
    {
//        YanchuSession session = yanchuSessionMapper.selectYanchuSessionById(id);
//        if (null != session && !Const.ZERO.equals(session.getStatus())){
//            throw new BaseException("该演出场次非创建中场次,不可删除");
//        }
        return yanchuSessionMapper.deleteYanchuSessionById(id);
    }


    @Override
    public int updateChecked(Integer count,Long id){
        logger.info("updateChecked count:{} id:{}",count,id);
        int countUpdate = yanchuSessionMapper.updateChecked(count,id);
        return countUpdate;
    }
    @Override
    public int down(Long id){
        logger.info("down id:{}",id);
        int countUpdate = yanchuSessionMapper.updateStatus(id,PerformConstants.SESSION_DOWN,null,null);
        if(countUpdate>0){
            yanchuSeatService.cancelTicketCache(id);
            redisCache.deleteObject(CacheConstants.TICKET_PRICE_LIST_KEY+id);//删除票档缓存
        }
        return countUpdate;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int cancel(Long id,String cancelTips){
        LoginUser loginUser = SecurityUtils.getLoginUser();
        logger.info("cancel id:{} cancelTips:{}",id,cancelTips);
        YanchuSession session = yanchuSessionMapper.selectYanchuSessionById(id);
        if(null == session){
            throw new ServiceException("场次不存在");
        }
        yanchuSeatMapper.deleteSeatBySessionId(id);//删除该场次座位
        int countUpdate = yanchuSessionMapper.updateCancel(id,PerformConstants.SESSION_CANCEL,null,cancelTips);
        if(countUpdate > 0) {
            session.setStatus(PerformConstants.SESSION_CANCEL);
            yanchuSeatService.cancelTicketCache(id);
            redisCache.deleteObject(CacheConstants.TICKET_PRICE_LIST_KEY+id);//删除票档缓存
        }else{
            throw new ServiceException("场次取消失败！");
        }
        YanchuOrder yanchuOrder = new YanchuOrder();
        yanchuOrder.setSessionId(id);
        //取消小程序订单
        iYanchuRefundOrderService.cancelOrderList(yanchuOrder,cancelTips,loginUser.getUser().getUserId(),session);
        //取消出票订单
        iYanchuRefundBackendOrderService.cancelOrderList(yanchuOrder,cancelTips,loginUser.getUser().getUserId(),session);
        return countUpdate;
    }

    /**
     * 待销售
     *
     * @return
     */
    @Override
    public List<YanchuSession> getToBeSold(Long operaId) {
        return yanchuSessionMapper.getToBeSold(operaId);
    }

    /**
     * 待销中
     *
     * @return
     */
    @Override
    public List<YanchuSession> getOnSale(Long operaId) {
        return yanchuSessionMapper.getOnSale(operaId);
    }

    /**
     * 待销结束
     *
     * @return
     */
    @Override
    public List<YanchuSession> getEndOfSale(Long operaId) {
        return yanchuSessionMapper.getEndOfSale(operaId);
    }

    /**
     * 所有存在场次的演出id
     *
     * @return
     */
    @Override
    public List<YanchuSession> getInPerForm(Long operaId) {
        return yanchuSessionMapper.getInPerForm(operaId);
    }

    /**
     * 售票前50的演出
     *
     * @return
     */
    @Override
    public List<Long> getFiftyOnsale() {
        return yanchuSessionMapper.getFiftyOnsale();
    }

    /**
     * 场次演出时间段内的演出
     *
     * @param startDate
     * @param endDate
     * @return
     */
    @Override
    public List<Long> getPerformByTime(Date startDate, Date endDate) {
        return yanchuSessionMapper.getPerformByTime(startDate,endDate);
    }

    /**
     * 场次列表pc
     *
     * @param yanchuSession
     * @return
     */
    @Override
    public List<YanchuSession> selectYanchuSessionBy(YanchuSession yanchuSession) {
        List<YanchuSession> sessions = yanchuSessionMapper.selectYanchuSessionBy(yanchuSession);
        //处理状态
        if (CollectionUtils.isNotEmpty(sessions)){
            sessions.forEach(s->{
                if (Const.ONE.equals(s.getStatus())) {
                    Date nowDate = DateUtils.getNowDate();
                    if (nowDate.compareTo(s.getTicketEnd()) > 0){
                        s.setStatus(5);
                    }
                    if (nowDate.compareTo(s.getTicketStart()) >= 0 && nowDate.compareTo(s.getTicketEnd()) <= 0){
                        s.setStatus(4);
                    }
                }
            });
        }
        return sessions;
    }

    /**
     * 复制场次
     *
     * @param yanchuSession
     * @return
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public int copySession(YanchuSession yanchuSession) {
        LoginUser user = SecurityUtils.getLoginUser();
        Long hallId = yanchuSession.getHallId();
        //新增场次
        int i = insertYanchuSession(yanchuSession);
        String copyType = yanchuSession.getCopyType();
        if (copyType.contains(Const.ONESTRING)){
            List<YanchuTicketPrice> prices = yanchuTicketPriceMapper.selectPriceList(yanchuSession.getCopyId());
            //复制票档设置和票房规划 （存在票房规划 必定需要存在票档设置）
            if (CollectionUtils.isNotEmpty(prices)){
                for (YanchuTicketPrice p : prices) {
                    p.setId(null);
                    p.setSessionId(yanchuSession.getId());
                    if (!copyType.contains(Const.THREESTRING)) {
                        p.setHasPromotion(null);
                        p.setTextPromotion(null);
                    }
                    if (!copyType.contains(Const.TWOSTRING)) {
                        p.setSeats(null);
                    }
                    p.setCreateTime(DateUtils.getNowDate());
                    p.setUpdateTime(null);
                    p.setCreateBy(user.getUserId() + "");
                    yanchuTicketPriceMapper.insertYanchuTicketPrice(p);
                }
            }
        }
        if (copyType.contains(Const.TWOSTRING)){
            //票房规划时  预留座处理
            TYanchuReservedTicket reservedTicket = new TYanchuReservedTicket();
            reservedTicket.setSessionId(yanchuSession.getCopyId());
            List<TYanchuReservedTicket> reservedTickets = yanchuReservedTicketMapper.selectTYanchuReservedTicketList(reservedTicket);
            if (CollectionUtils.isNotEmpty(reservedTickets)){
                reservedTickets.forEach(r ->{
                    r.setId(null);
                    r.setHallId(hallId);
                    r.setSessionId(yanchuSession.getId());
                    r.setCreatTime(DateUtils.getNowDate());
                    r.setUpdateTime(null);
                    yanchuReservedTicketMapper.insertTYanchuReservedTicket(r);
                });
            }
        }
        return i;
    }

    /**
     * 小程序查询场次（验票端）
     *
     * @param time
     * @param operaId
     * @return
     */
    @Override
    public List<SessionTicketVO> ticketList(String time, Long operaId) {
        Date dayOfMonthEndTime = DateUtils.getLastDayOfMonth(DateUtils.parseDate(time));
        Date dayStartTime = DateUtils.getFirstDayOfMonth(DateUtils.parseDate(time));
        List<YanchuSession> sessions = yanchuSessionMapper.ticketList(dayStartTime, dayOfMonthEndTime, operaId);
        if (CollectionUtils.isEmpty(sessions)){
            return Collections.emptyList();
        }
        List<String> dateTime = sessions.stream().map(s -> DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, s.getPlayTime())).distinct().collect(Collectors.toList());
        List<SessionTicketVO> vos = new ArrayList<>();
        dateTime.forEach(d -> {
            SessionTicketVO vo = new SessionTicketVO();
            vo.setTime(d);
            List<YanchuSession> session = new ArrayList<>();
            sessions.forEach(s ->{
                if (d.equals(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, s.getPlayTime()))){
                    session.add(s);
                }
            });
            vo.setSessions(session.stream().sorted(Comparator.comparing(YanchuSession::getPlayTime)).collect(Collectors.toList()));
            vos.add(vo);
        });
        return vos;
    }

    /**
     * 小程序演出开场消息提醒
     */
    @Override
    public void notifyUserOrder() {
        logger.info("notifyUserOrder");
        List<YanchuSession> list = yanchuSessionMapper.selectRemindSessionList();
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        List<OrderVo> orders = null;
        YanchuOrder yanchuOrder = null;
        if (!wxMaService.switchover("wx839ab821b194d9d0")) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", "wx839ab821b194d9d0"));
        }
        for (YanchuSession session : list) {
            try {
                yanchuOrder = new YanchuOrder();
                yanchuOrder.setSessionId(session.getId());
                yanchuOrder.setStatus(PerformConstants.ORDER_PAY);
                orders = yanchuOrderMapper.selectUserReminderOrderVoList(yanchuOrder);
                if(CollectionUtils.isNotEmpty(orders)){
                    String performName = null;
                    for (OrderVo vo : orders) {
                        if(StringUtils.isEmpty(vo.getOpenId())){
                            continue;
                        }
                        performName = vo.getPerformVo().getPerformName();
                        if(performName.length()>20){
                            performName = performName.substring(0,17)+"...";
                        }
                        logger.info("notifyUserOrder openId{} name:{}",vo.getOpenId(),performName);
                        wxMaService.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
                                .templateId(templateId)
                                .data(Lists.newArrayList(
                                        new WxMaSubscribeMessage.MsgData("thing1", performName),
                                        new WxMaSubscribeMessage.MsgData("date2", DateUtils.dateTimeHour(vo.getSessionVo().getPlayTime())),
                                        new WxMaSubscribeMessage.MsgData("thing3", vo.getSessionVo().getHallName()),
                                        new WxMaSubscribeMessage.MsgData("thing6", "请在演出开始前30分钟检票入场")))
                                .page("/pages/ticketFolderDetail/index?id="+vo.getId())
                                .miniprogramState(miniprogramState)
                                .toUser(vo.getOpenId())
                                .build());
                    }
                }
                session.setReminded(1);
                yanchuSessionMapper.updateYanchuSession(session);
            }catch (Exception e){
                logger.error("notifyUserOrder error",e);
            }
        }
    }

    @Override
    public List<String> dateList(Long operaId) {
        Date startDay = DateUtils.parseDate("2023-12-01");
        Date endTDay = DateUtils.getAddOneYear(new Date());
        return yanchuSessionMapper.getSessionsByOperaId(operaId,startDay,endTDay);
    }

    @Autowired
    public YanchuSessionServiceImpl(WxMaService wxMaService) {
        this.wxMaService = wxMaService;
    }
}
